//-------------------------------------------------------------------------------------------------
// container.hpp - Introduces streaming operators to insert/remove items to/from containers.
//-------------------------------------------------------------------------------------------------

#pragma once

#include <vector>
#include <queue>
#include <stack>
#include <list>

#include "auto_list.hpp"
#include "meta_set.hpp"




namespace boostext
{
	/**
	 * @brief   Insert a value into a std::set.
	 */
	template
	<
		typename _Ty,
		typename _Tx,
		typename _Pr,
		class _Ax
	>
	std::set<_Ty,_Pr, _Ax> operator<<(std::set<_Ty,_Pr,_Ax>& _Cont, const _Tx& _Val)
	{
		_Cont.insert(_Val);
		return _Cont;
	}

	/**
	 * @brief   Insert a value into a boost_ext::meta_set.
	 */
	template
	<
		typename _Ty,
		typename _Meta,
		_Meta    _DefaultMeta,
		typename _Tx,
		typename _Pr,
		class _Ax
	>
	meta_set<_Ty,_Meta,_DefaultMeta,_Pr, _Ax> operator<<(meta_set<_Ty,_Meta,_DefaultMeta,_Pr,_Ax>& _Cont, const _Tx& _Val)
	{
		_Cont.insert(_Val);
		return _Cont;
	}

	/**
	 * @brief   Insert a meta_pair into a boost_ext::meta_set.
	 */
	template
	<
		typename _Ty,
		typename _Meta,
		_Meta    _DefaultMeta,
		typename _Tx,
		typename _Pr,
		class _Ax
	>
	meta_set<_Ty,_Meta,_DefaultMeta,_Pr, _Ax> operator<<(meta_set<_Ty,_Meta,_DefaultMeta,_Pr,_Ax>& _Cont, const typename meta_set<_Ty,_Meta,_DefaultMeta,_Pr,_Ax>::meta_pair& _Val)
	{
		_Cont.insert(_Val);
		return _Cont;
	}

	/**
	 * @brief   Add a value to the end of a std::vector.
	 *
	 * This function even accepts a value of a different type, than the vector stores.
	 * Only converts the two types, if they can be converted implicitly.
	 */
	template
	<
		typename _Ty,
		typename _Tx,
		class _Ax
	>
	std::vector<_Ty,_Ax>& operator<<(std::vector<_Ty,_Ax>& _Cont, const _Tx& _Val)
	{
		_Cont.push_back(_Val);
		return _Cont;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////




	/**
	 * @brief   Add a value to the end of a std::list.
	 *
	 * This function even accepts a value of a different type, than the list stores.
	 * Only converts the two types, if they can be converted implicitly.
	 */
	template
	<
		typename _Ty,
		typename _Tx,
		class _Ax
	>
	std::list<_Ty,_Ax>& operator<<(std::list<_Ty,_Ax>& _Cont, const _Tx& _Val)
	{
		_Cont.push_back(_Val);
		return _Cont;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////




	/**
	 * @brief   Add a value to the end of a boost_plus::list.
	 *
	 * This function even accepts a value of a different type, than the list stores.
	 * Only converts the two types, if they can be converted implicitly.
	 */
	template
	<
		typename _Ty,
		typename _Tx,
		class _Ax
	>
	auto_list<_Ty,_Ax>& operator<<(auto_list<_Ty,_Ax>& _Cont, const _Tx& _Val)
	{
		_Cont.push_back(_Val);
		return _Cont;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * @brief   Splice one auto_list to the end of another one.
	 *
	 * Removes all nodes from _Right and inserts them at the end of _Left.
	 */
	template
	<
		typename _Ty,
		class _Ax
	>
	auto_list<_Ty,_Ax>& operator<<(auto_list<_Ty,_Ax>& _Left, auto_list<_Ty,_Ax>& _Right)
	{
		_Left.splice(_Left.end(),_Right);
		return _Left;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////




	/**
	 * Add a value to the end of a std::queue.
	 * This function even accepts a value of a different type, than the queue stores.
	 * Only converts the two types, if they can be converted implicitly.
	 */
	template
	<
		typename _Ty,
		typename _Tx,
		class _Ax
	>
	std::queue<_Ty,_Ax>& operator<<(std::queue<_Ty,_Ax>& _Cont, const _Tx& _Val)
	{
		_Cont.push( _Val );
		return _Cont;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Remove and retrieve an element from the \b front of the queue.
	 * This function even accepts a value of a different type, than the queue stores.
	 * Only converts the two types, if they can be converted implicitly.
	 */
	template
	<
		typename _Ty,
		typename _Tx,
		class _Ax
	>
	std::queue<_Ty,_Ax>& operator>>(std::queue<_Ty,_Ax>& _Cont, _Tx& _Val)
	{
		_Val = _Cont.front();
		_Cont.pop();
		return _Cont;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////




	/**
	 * Add a value to the top of the stack.
	 * This function even accepts a value of a different type, than the stack stores.
	 * Only converts the two types, if they can be converted implicitly.
	 */
	template
	<
		typename _Ty,
		typename _Tx,
		class _Ax
	>
	std::stack<_Ty,_Ax>& operator<<(std::stack<_Ty,_Ax>& _Cont, const _Tx& _Val)
	{
		_Cont.push(_Val);
		return _Cont;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Remove and retrieve the topmost value from the stack.
	 * This function even accepts a value of a different type, than the stack stores.
	 * Only converts the two types, if they can be converted implicitly.
	 */
	template
	<
		typename _Ty,
		typename _Tx,
		class _Ax
	>
	std::stack<_Ty,_Ax>& operator>>(std::stack<_Ty,_Ax>& _Cont, _Tx& _Val)
	{
		_Val = _Cont.top();
		_Cont.pop();
		return _Cont;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
